﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Servidor.WebServices;
using TiposComuns.Objectos;
using System.Runtime.Remoting.Messaging;
using System.IO;
using System.Xml.Serialization;
using System.Net;

namespace Servidor.Interface
{
    delegate State Connect(int id,Person person);
    delegate void CallbackCon(State state);
    delegate void ErrorDelegate(Exception e);
    

    delegate void LogDelegate(string msg);

    public partial class Init : Form
    {
        private ActionDelegate actionDelegate;
        private bool sIniciado = false;
        public Init()
        {
            InitializeComponent();
            InitInfo();
            actionDelegate = new ActionDelegate(LogCallback);
            Proxy.GetInstance().ActionDelegate += actionDelegate;
        }

        private void Init_Load(object sender, EventArgs e)
        {
            
        }

        private void LogCallback(string msg)
        {
            this.Invoke(new LogDelegate(Log),msg);
        }

        private void Log(string msg)
        {
            this.logfile.AppendText(msg+System.Environment.NewLine);
        }

        private void InitInfo()
        {
            string strHostName = Dns.GetHostName ();
              
            IPHostEntry ipEntry = Dns.GetHostEntry(strHostName);
            IPAddress [] addr = ipEntry.AddressList;

            foreach(IPAddress ip in addr)
            {
                if (ip.GetAddressBytes().Length==4)
                {
                    tb_address.Text = "tcp://" + ip.ToString();
                }
            }
        }

        private void b_start_Click(object sender, EventArgs e)
        {            
            if (tb_address.Text.Length == 0)
            {
                MessageBox.Show("Tem de introduzir um endereço", "Erro", MessageBoxButtons.OK);
                return;
            }

            if (tb_username.Text.Length == 0)
            {
                MessageBox.Show("Tem de introduzir um username", "Erro", MessageBoxButtons.OK);
                return;
            }

            b_start.Enabled = false;
            Cursor = Cursors.WaitCursor;
            
            Person person = new Person(tb_username.Text,new Address(tb_address.Text,(int)(tb_port.Value)));
            person.LastAccess = DateTime.Now;

            AsyncCallback async = new AsyncCallback(CallBack);
            Connect con = new Connect(Proxy.GetInstance().Init);
            con.BeginInvoke((int)tb_id.Value-1,person,async,null);
            
        }

        private void tb_port_ValueChanged(object sender, EventArgs e)
        {
            decimal value = tb_port.Value;
            value = Math.Round(value / 10,0) * 10;
            tb_port.Value = value;            
        }

        private void Finish(State state)
        {            
            b_start.Enabled = true;
            Cursor = Cursors.Default;
            if (state != null)
            {
                Proxy.GetInstance().ActionDelegate -= actionDelegate;
                Person person = new Person(tb_username.Text, new Address(tb_address.Text, (int)(tb_port.Value + tb_id.Value)));
                StateForm sf = new StateForm(state, tb_id.Value, person, logfile.Text);
                sf.Text = person.Username + " " + (tb_port.Value + tb_id.Value) + " (S" + tb_id.Value + ")";
                sf.Show(this);
                this.Visible = false;
                sIniciado = true;
                
            }
            else MessageBox.Show("Não foi possível iniciar o servidor");
        }

        private void Error(Exception e)
        {
            MessageBox.Show(e.Message,"Error");
            this.Cursor = Cursors.Default;
            b_start.Enabled = true;
        }

        private void CallBack(IAsyncResult res)
        {
            try
            {
                Connect con = ((AsyncResult)res).AsyncDelegate as Connect;
                State state = con.EndInvoke(res);
                CallbackCon cbc = new CallbackCon(Finish);

                this.Invoke(cbc, state);
            }
            catch (Exception e)
            {
                this.Invoke(new ErrorDelegate(Error),e);
            }
        }

        private void Init_VisibleChanged(object sender, EventArgs e)
        {
            if (this.Visible == true && sIniciado == true)
                this.Close();
        }
    }
}
